#ifndef VISCOMPONENTSTRATEGY_H
#define VISCOMPONENTSTRATEGY_H

#pragma once

#include <LDF/LargeDisplayFrameworkLayer.h>
#include <vector>


// Forward declarations to avoid including classes that only the name is needed
// in here and to avoid double including
class VisComponent;
class LargeDisplayEvent;


/**
 * This class defines the interface of a strategy used for the behavior of a
 * component. Its concrete subclasses determine how to draw the component and
 * how it should respond to events.
 *
 * @author Fabricio Anastacio - fabriciocfa@yahoo.com
 * @since July 2, 2007
 */
class LARGEDISPLAYFRAMEWORKLAYER_API VisComponentStrategy
{
	// Attributes
protected:
	/** The VisComponent object using this strategy. */
	VisComponent* component;
	/** The VisComponentStrategy object that is next to this one in the
	 * processing order or that is "decorated" by this one, if any. */
	VisComponentStrategy* nextStrategy;


	// Methods
public:
	/**
	 * Constructs this startegy.
	 */
	VisComponentStrategy(void);
	/**
	 * Destroys this strategy.
	 */
	virtual ~VisComponentStrategy(void);


	// METHODS CALLED BY THE COMPONENT (CONSIDERING DECORATORS)
	/**
	 * Initializes the properties (i. e., i-buffers) of the associated
	 * component.
	 */
	inline void initPropertiesComponent() {
		if (nextStrategy) nextStrategy->initPropertiesComponent(); initProperties();
	};
	/**
	 * Performs an action before drawing the component.
	 */
	inline void processComponent() {
		if (nextStrategy) nextStrategy->processComponent(); process();
	};
	/**
	 * Defines the drawing strategy for the associated component.
	 *
	 * @param selectedIds the list of currently selected ids.
	 */
	inline void drawComponent(const std::vector<unsigned long>& selectedIds) {
		if (nextStrategy) nextStrategy->drawComponent(selectedIds); draw(selectedIds);
	};
	/**
	 * Defines the drawing strategy for the associated component to be used for
	 * picking.
	 */
	inline void drawForPickingComponent() {
		if (nextStrategy) nextStrategy->drawForPickingComponent(); drawForPicking();
	};
	/**
	 * Handles the given event.
	 *
	 * @param evt the event to be handled.
	 */
	inline void onEventComponent(LargeDisplayEvent* evt) { 
		if (nextStrategy) nextStrategy->onEventComponent(evt); onEvent(evt);
	}
	/**
	 * Defines the strategy to be used when the associated component is
	 * resized.
	 *
	 * @param width the new width of the component.
	 * @param height the new height of the component.
	 */
	inline void resizeComponent(unsigned int width, unsigned int height) {
		if (nextStrategy) nextStrategy->resizeComponent(width, height); resize(width, height);
	};
	/**
	 * Defines the strategy to be used when the associated component is dropped
	 * inside another component/container. Returns true if this call resulted
	 * in adding the component to a container with animation.
	 *
	 * @param parentChanged true if the component's parent changed with the
	 * dropping.
	 * @return true if this call resulted in adding the component to a
	 * container with animation, false otherwise.
	 */
	inline bool dropComponent(bool parentChanged) { bool r = false; 
		if (nextStrategy) r = nextStrategy->dropComponent(parentChanged) || r;
		return (drop(parentChanged) || r);
	};
	/**
	 * Reads the passive buffer(s) specified by the parameter 'type' and makes
	 * the proper updates in the state of the associated component.
	 * The value of type must be unique for each type of buffer throughout the
	 * application. Inconsistences can lead to unexpected behaviors during
	 * buffer reading.
	 *
	 * @param types the types of buffers that should be read from the container.
	 */
	inline void readPassiveBuffersComponent(const std::vector<unsigned int>& types) {
		if (nextStrategy) nextStrategy->readPassiveBuffersComponent(types); readPassiveBuffers(types);
	};
	/**
	 * Reads all the passive buffers for a component specified by its
	 * associated strategies. This method is called before drawing the
	 * component in order to update its state/properties.
	 */
	inline void readAllPassiveBuffersComponent() {
		if (nextStrategy) nextStrategy->readAllPassiveBuffersComponent(); readAllPassiveBuffers();
	};
	/**
	 * Reads only the passive buffers for the component strategies that are
	 * necessary for picking processing. This method is called before drawing
	 * the component for picking in order to update its state/properties.
	 */
	inline void readAllPickingPassiveBuffersComponent() {
		if (nextStrategy) nextStrategy->readAllPickingPassiveBuffersComponent(); readAllPickingPassiveBuffers();
	};

	
	// ACCESSOR METHODS
	/**
	 * Sets the component associated with this strategy.
	 *
	 * @param comp the VisComponent object associated with this strategy.
	 */
	inline void setComponent(VisComponent* comp) { component = comp; };
	/**
	 * Returns a pointer to the component associated with this strategy.
	 *
	 * @return a pointer to the component associated with this strategy.
	 */
	inline VisComponent* getComponent() { return component; };
	/**
	 * Sets the next strategy to this one (Decorator Design Pattern).
	 *
	 * @param next the VisComponentStrategy object that is next to this
	 * strategy.
	 */
	inline void setNextStrategy(VisComponentStrategy* next) { nextStrategy = next; };
	/**
	 * Returns a pointer to the strategy that is necxt to this one (Decorator
	 * Design Pattern).
	 *
	 * @return a pointer to the strategy that is necxt to this one.
	 */
	inline VisComponentStrategy* getNextStrategy() { return nextStrategy; };


protected:
	// VIRTUAL METHODS
	/**
	 * Initializes the properties (i. e., i-buffers) of the associated
	 * component.
	 */
	inline virtual void initProperties() {};
	/**
	 * Performs a given action before rendering the component.
	 */
	inline virtual void process() {};
	/**
	 * Defines the drawing strategy for the associated component.
	 *
	 * @param selectedIds the list of currently selected ids.
	 */
	inline virtual void draw(const std::vector<unsigned long>& selectedIds) {};
	/**
	 * Defines the drawing strategy for the associated component that should be
	 * used for picking.
	 */
	inline virtual void drawForPicking() {};
	/**
	 * Handles the given event.
	 *
	 * @param evt the event to be handled.
	 */
	inline virtual void onEvent(LargeDisplayEvent* evt) {};
	/**
	 * Defines the strategy to be used when the associated component is
	 * resized.
	 *
	 * @param width the new width of the component.
	 * @param height the new height of the component.
	 */
	inline virtual void resize(unsigned int width, unsigned int height) {};
	/**
	 * Defines the strategy to be used when the associated component is
	 * "dropped" inside another component (likely, a container). It is called
	 * when the component is processed from the manager's update list. It
	 * usually defines some "decorative" behavior such as triggering
	 * animations, since the composition structure is already managed by the
	 * LargeDisplayManager class. Returns true if this call resulted in
	 * adding the component to a container with animation.
	 *
	 * @param parentChanged true if the component's parent changed with the
	 * dropping.
	 * @return true if this call resulted in adding or keeping the component to
	 * a container with animation, false otherwise.
	 */
	inline virtual bool drop(bool parentChanged) { return false; };
	/**
	 * Reads the passive buffer(s) specified by the parameter 'type' and makes
	 * the proper updates in the state of the associated component.
	 * The value of type must be unique for each type of buffer throughout the
	 * application. Inconsistences can lead to unexpected behaviors during
	 * buffer reading.
	 *
	 * @param types the types of buffers that should be read from the container.
	 */
	inline virtual void readPassiveBuffers(const std::vector<unsigned int>& types) {};
	/**
	 * Reads all the passive buffers for a component strategy. This method is
	 * called before drawing the component in order to update its
	 * state/properties.
	 */
	inline virtual void readAllPassiveBuffers() {};
	/**
	 * Reads only the passive buffers for a component strategy that are
	 * necessary for picking processing. This method is called before drawing
	 * the component for picking in order to update its state/properties.
	 */
	inline virtual void readAllPickingPassiveBuffers() {};

};

#endif // VISCOMPONENTSTRATEGY_H
